﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;

namespace INFDTM01.Models
{
    public class UserPreference
    {
        public int UserId { get; set; }
        public int[] ItemIds { get; set; }
        public float[] Preferences { get; set; }

        public void setItemIdRating(int itemId, float rating)
        {
            // Eerst checken of de item id al een rating heeft want dan kun je deze direct vervangen.
            int index = getItemIdIndex(ItemIds, itemId);
            if (index >= 0)
            {
                ItemIds[index] = itemId;
                Preferences[index] = rating;
            }
            else
            {
                ItemIds = insertItemId(ItemIds, itemId);
                Preferences = insertPreferenceId(Preferences, rating);
                sortItemsAndPreferences();
            }
        }
        
        /*
         *   6 9  15   => 3 begin  , 23 aanhet eind
         *     11 ? ergens   binsearch invul indexplaats
         *          copy 6  9    11  copy  15
         *   
         * 
         * Indien de array nog niet bestaat wordt deze aangemaakt en wordt het element in index[0] gezet.
         * Mocht de array al bestaan, wordt deze met 1 element vergroot en wordt het element op de hoogste index gezet.
         * 
         */
        private int[] insertItemId(int[] original, int element)
        {
            if (original == null)
            {
                original = new int[1];
                original[0] = element;
                
                return original;
            }

            int length = original.Count();
            int[] destination = new int[length + 1];
            
            Array.Copy(original, 0, destination, 0, length);
            destination[length] = element;
            
            return destination;
        }

        /*
         * Indien de array nog niet bestaat wordt deze aangemaakt en wordt het element in index[0] gezet.
         * Mocht de array al bestaan, wordt deze met 1 element vergroot en wordt het element op de hoogste index gezet.
         * 
         */
        private float[] insertPreferenceId(float[] original, float element)
        {
            if (original == null)
            {
                original = new float[1];
                original[0] = element;

                return original;
            }

            int length = original.Count();
            float[] destination = new float[length + 1];

            Array.Copy(original, 0, destination, 0, length);
            destination[length] = element;

            return destination;
        }

        /*
         * Checkt of de "item id" al bestaat en als die bestaat returned die de index.
         * Dit is belangrijk omdat we dan de bestaande gegevens kunnen vervangen.
         * 
         */
        public int getItemIdIndex(int[] itemIds, int itemId)
        {  //binary search
            int index = -1;
            if (itemIds == null)
            {
                return index;
            }

            //for (int i = 0; i < itemIds.Count(); i++)
            //{
            //    if (itemIds[i] == itemId)
            //    {
            //        index = i;
            //        break;
            //    }
            //}

            index = Array.BinarySearch(itemIds, itemId);

            return index;
        }

        /*
         * Loop door de gesorteerde "item ids" en zet bij iedere index de "item id" in de variabele "sortedItemId";
         * Loop vervolgens door de ongesorteerde "item ids" en check of de ongesoorteerde "item id" overeenkomt met de "sortedItemId";
         * Zo ja, dan weet je de index van de preference die bij de gesorteerde "item id" hoort.
         * 
         * In kort: de "item id" wordt gesorteerd; de rating wordt bij de "item id" horende index gesorteerd.
         * 
         */
        public void sortItemsAndPreferences()
        {
            //int[] unsortedItems = new int[ItemIds.Count()];
            //ItemIds.CopyTo(unsortedItems, 0);

            //int[] sortedItems = ItemIds;
            //float[] sortedPrefs = Preferences;
            //Array.Sort(sortedItems);
            ////Array.Sort(sortedPrefs, sortedItems);

            //float[] unsortedPreferences = new float[Preferences.Count()];
            //Preferences.CopyTo(unsortedPreferences, 0);

            //float[] sortedPreferences = new float[Preferences.Count()];

            //for (int i = 0; i < sortedItems.Count(); i++)
            //{
            //    int sortedItemId = sortedItems[i];

            //    for (int j = 0; j < unsortedItems.Count(); j++)
            //    {
            //        if (unsortedItems[j] == sortedItemId)
            //        {
            //            sortedPreferences[i] = unsortedPreferences[j];
            //            break;
            //        }
            //    }
            //}

            var sortedPairs = Preferences.Select((x, i) => new { Value = x, Key = ItemIds[i] })
                        .OrderBy(x => x.Key)
                        .ThenBy(x => x.Value)
                        .ToArray(); // this avoids sorting 2 times...
            float[] sortedValues = sortedPairs.Select(x => x.Value).ToArray();
            int[] sortedKeys = sortedPairs.Select(x => x.Key).ToArray();

            ItemIds = sortedKeys;
            Preferences = sortedValues;
        }

        /*
         * Params:
         *          int[] itemsPerson1
         *          int[] itemsPerson2
         * 
         * Returns:
         *          int[] relatedItems
         * 
         * Vergelijkt 'itemsPerson1' met 'itemsPerson2' en zet de items die ze beide hebben in een nieuwe array.
         * 
         */
        public int[] getIndenticalItems(int[] userItems)
        {
            int[] indenticalItems;
            List<int> items = new List<int>();

            for (int i = 0; i < userItems.Length; i++)
            {
                for (int j = 0; j < this.ItemIds.Length; j++)
                {
                    if (userItems[i] == this.ItemIds[j])
                    {
                        items.Add(userItems[i]);
                    }
                }
            }

            indenticalItems = items.ToArray();

            return indenticalItems;
        }
    }
}